#ifndef _AST_H_
#define _AST_H_

#include "symbol.h"

typedef struct st_ast_exp       *ast_exp;

typedef struct st_ast_varref    *ast_varref;

typedef struct st_ast_type      *ast_type;

typedef struct st_ast_decl_var  *ast_decl_var;

typedef struct st_ast_decl_type *ast_decl_type;

typedef struct st_ast_decl_func *ast_decl_func;

typedef struct st_ast_explist   *ast_explist;

typedef struct st_ast_decl_varlist  *ast_decl_varlist;

typedef enum { A_PLUS, A_MINUS, A_TIMES, A_DIVIDE, A_EQ, A_NEQ,
                A_GT, A_LT, A_GE, A_LE, A_AND, A_OR,
                 A_ADDR,A_DEREF } ast_oper ;

struct st_ast_exp {
    enum { A_VARREF, A_NIL, A_INTC, A_STRINGC, A_CALL,
            A_OP, A_DECL_VAR, A_DECL_TYPE, A_DECL_FUNC,
             A_ASSIGN, A_SEQ, A_IF, A_WHILE, A_BREAK } kind;
    union {
        ast_varref var_r;
        /* nil */
        int intc;
        symbol stringc;
        struct {
            symbol func;
            ast_explist args;
        } call;
        struct {
            ast_oper oper;
            ast_exp left, right;
        } op;
        ast_decl_var decl_var;
        ast_decl_type decl_type;
        ast_decl_func decl_func;
        struct {
            ast_varref var_w;
            ast_exp exp;
        } assign;
        ast_explist seq;
        struct { ast_exp cond, then, elsee; } iff;
        struct { ast_exp cond, body; } whilee;
        /* break */
    } u;
};

struct st_ast_varref {
    enum { A_SIMPLE, A_FIELD, A_SUBSCRIPT } kind;
    union {
        symbol simple_ref;
        struct {
            ast_varref var;
            symbol field_name;
        } field_ref;
        struct {
            ast_varref var;
            ast_exp subs;
        } subs_ref;
    } u;
};

struct st_ast_type {
    enum { A_STRUCT, A_ARRAY, A_ALIAS, A_INTT, A_STRINGT } kind;
    union {
        ast_decl_varlist structt;
        ast_type arrayt;
        symbol alias;
        /* intt */
        /* stringt */
    } u;
};

struct st_ast_decl_var {
    ast_type typee;
    symbol var;
    ast_exp exp;
};

struct st_ast_decl_type {
    symbol alias;
    ast_type type;
};

struct st_ast_decl_func {
    ast_type resultt;
    ast_decl_varlist args;
    symbol func;
    ast_exp body;
};

struct st_ast_explist {
    ast_exp exp;
    ast_explist next;
};

struct st_ast_decl_varlist {
    ast_decl_var decl_var;
    ast_decl_varlist next;
};

#endif